package etc.service.impl;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.ftp.Ftp;
import com.dmz.test.etc.config.DmzProp;
import com.dmz.test.etc.config.EnvConfig;
import com.dmz.test.etc.config.enums.AnsCode;
import com.dmz.test.etc.config.enums.MsgType;
import com.dmz.test.etc.config.enums.RecordCode;
import com.dmz.test.etc.domain.ClientTask;
import com.dmz.test.etc.domain.MsgClazz;
import com.dmz.test.etc.domain.MsgHeader;
import com.dmz.test.etc.netty.attr.ChannelAttrs;
import com.dmz.test.etc.service.ClientService;
import com.dmz.test.etc.utils.FileUtil;
import com.dmz.test.etc.utils.etc.DateTools;
import com.dmz.test.etc.utils.etc.PackTool;
import com.dmz.test.etc.utils.ftp.FtpClient;
import com.dmz.test.etc.utils.ftp.FtpFile;
import com.dmz.test.etc.utils.ftp.FtpUtil;
import com.dmz.test.etc.utils.secure.CryptoUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * @author lee
 */
@Service
@Slf4j
public class ClientServiceImpl implements ClientService {

    @Resource
    private DmzProp dmzProp;

    @Resource
    private PackTool packTool;


    @Override
    public MsgClazz send(ClientTask task, Channel c) {
        MsgHeader header = createHeader(task);
        MsgClazz msgClazz = handleMsgType(task, c, header);
        msgClazz.setToc(true);
        return msgClazz;
    }

    private MsgHeader createHeader(ClientTask task) {
        MsgHeader header = new MsgHeader();
        header.setSenderId(dmzProp.getEtcId());
        header.setReceiverId(dmzProp.getBankId());
        header.setMessageType(task.getMsgPhase().getType());
        return header;
    }

    private MsgClazz handleMsgType(ClientTask task, Channel c, MsgHeader header) {
        StringBuilder reqBodyStr = new StringBuilder(DateTools.getDateTimeString());
        if (MsgType.TYPE_1001.equals(task.getMsgPhase())) {
            return handleType1001(header, reqBodyStr);
        } else if (MsgType.TYPE_1003.equals(task.getMsgPhase())) {
            return handleType1003(c, header, reqBodyStr);
        } else {
            return handleFileType(task, c, header, reqBodyStr);
        }
    }

    private MsgClazz handleType1001(MsgHeader header, StringBuilder reqBodyStr) {
        MsgClazz msgClazz = new MsgClazz();
        log.info("client--1001--req--body:{}", reqBodyStr);
        header.setMessageId(StrUtil.padPre(String.valueOf(1), 4, header.getPadStr()));
        try {
            byte[] bytes = packTool.packSet(reqBodyStr.toString(), packTool.getKeyBytes(), header);
            log.info("task--client---send----1001--data:{}", bytes);
            msgClazz.setData(bytes);
        } catch (Exception e) {
            log.error("报文{}发送异常！", header.getMessageType(), e);
        }
        return msgClazz;
    }

    private MsgClazz handleType1003(Channel c, MsgHeader header, StringBuilder reqBodyStr) {
        MsgClazz msgClazz = new MsgClazz();
        reqBodyStr.append(dmzProp.getNetworkId()).append(dmzProp.getTerminalId());
        log.info("client--1003--req--body:{}", reqBodyStr);
        header.setMessageId(StrUtil.padPre(String.valueOf(3), 4, header.getPadStr()));
        try {
            byte[] key = c.attr(ChannelAttrs.dynamicKey).get();
            byte[] reqMsg = packTool.packSet(reqBodyStr.toString(), key, header);
            log.info("task--client---send----1003--data:{}", reqMsg);
            msgClazz.setData(reqMsg);
        } catch (Exception e) {
            log.error("报文1003发送异常！", e);
        }
        return msgClazz;
    }

    private MsgClazz handleFileType(ClientTask task, Channel c, MsgHeader header, StringBuilder reqBodyStr) {
        MsgClazz msgClazz = new MsgClazz();
        FtpFile ftpFile = task.getFtpFile();
        header.setMessageId(StrUtil.padPre(String.valueOf(5), 4, header.getPadStr()));
        reqBodyStr.append(dmzProp.getNetworkId()).append(dmzProp.getTerminalId());
        reqBodyStr.append(DateTools.getDateStr()).append(dmzProp.getBankId()).append(StrUtil.padAfter(ftpFile.getFileName(), 36, " "));
        File file = FileUtil.file(ftpFile.getLocalPath() + ftpFile.getFileName());

        FileReader fileReader = new FileReader(file, dmzProp.getDefaultEncoding());
        List<String> lines = fileReader.readLines();
        //reqBodyStr.append(StrUtil.padPre(String.valueOf(lines.size()), 6, header.getPadStr()));
        int ln = -1;
        int flag = 0;
        String num = "0";
        String rt = "00000000000000000000000000000000000000000000000000000" + DateTools.getDateStr();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            String[] records = line.split("\\|");
            if (header.getMessageType().equals(MsgType.TYPE_2051.getType()) && RecordCode.CODE_3003.getCode().equals(records[0])) {
                reqBodyStr.append(StrUtil.padPre(records[1], 6, header.getPadStr()));
                break;
            }
            if (header.getMessageType().equals(MsgType.TYPE_4031.getType()) && RecordCode.CODE_4002.getCode().equals(records[0])) {
                reqBodyStr.append(StrUtil.padPre(records[1], 6, header.getPadStr()));
                break;
            }


            if (header.getMessageType().equals(MsgType.TYPE_4051.getType())) {
                if (RecordCode.CODE_5003.getCode().equals(records[0])) {
                    ln = i + 1;
                    flag ++;
                }

                if(RecordCode.CODE_5004.getCode().equals(records[0])) {
                    num = StrUtil.padPre(records[1], 6, header.getPadStr());
                    flag ++;
                }

                if(ln == i) {
                    rt = line.substring(15).replace("|", "");
                    flag ++;
                }
                if(flag == 3) {
                    reqBodyStr.append(StrUtil.padPre(num, 6, header.getPadStr())).append(rt);
                    break;
                }
            }
        }

        //reqBodyStr.append(StrUtil.padPre(num, 6, header.getPadStr()));

        String md5 = SecureUtil.md5(file);
        reqBodyStr.append(md5);
        try {
            byte[] key = c.attr(ChannelAttrs.dynamicKey).get();
            byte[] reqMsg = packTool.packSet(reqBodyStr.toString(), key, header);
            boolean b = uploadFile(ftpFile);
            msgClazz.setData(reqMsg);
            msgClazz.setSend(b);
            log.info("client--{}--req--body:{}", task.getMsgPhase(), reqBodyStr);
        } catch (Exception e) {
            log.error("报文2051发送异常！", e);
        }
        return msgClazz;
    }

    @Override
    public MsgClazz receive(ClientTask task, Channel c, byte[] msg) {
        MsgHeader mh = new MsgHeader();
        MsgClazz msgClazz = new MsgClazz();
        byte[] resHead = new byte[58];
        if (msg != null && msg.length > 0) {
            System.arraycopy(msg, 0, resHead, 0, 58);
            mh.analyze(resHead);
            byte[] resBody = new byte[msg.length - 58];
            System.arraycopy(msg, 58, resBody, 0, msg.length - 58);
            String ansCode = extractAnsCode(mh.getMessageType(), c, resBody);
            if (AnsCode.CODE_00.getCode().equals(ansCode)) {
                if (MsgType.TYPE_1002.getType().equals(mh.getMessageType())) {
                    task.setMsgPhase(MsgType.TYPE_1003);
                } else if (MsgType.TYPE_1004.getType().equals(mh.getMessageType())) {
                    task.setMsgPhase(task.getMsgType());
                } else {
                    msgClazz.setToc(false);
                }
                msgClazz = send(task, c);
            }
        }
        return msgClazz;
    }

    private String extractAnsCode(String messageType, Channel c, byte[] resBody) {
        byte[] decrypt;
        try {
            if (MsgType.TYPE_1002.getType().equals(messageType)) {
                byte[] key = packTool.getKeyBytes();
                decrypt = CryptoUtil.decrypt(resBody, key);
                byte[] keyBytes = new byte[16];
                System.arraycopy(decrypt, 16, keyBytes, 0, 16);
                byte[] dynamicKey = CryptoUtil.getKey(keyBytes);
                c.attr(ChannelAttrs.dynamicKey).set(dynamicKey);
                log.info("报文类型为{}解密因子为{}", messageType, packTool.getKeyBytes());

            } else {
                byte[] key = c.attr(ChannelAttrs.dynamicKey).get();
                decrypt = CryptoUtil.decrypt(resBody, key);
                log.info("报文类型为{}解密因子为{}", messageType, key);
            }

            byte[] ansCodeBytes = new byte[2];
            System.arraycopy(decrypt, 14, ansCodeBytes, 0, 2);
            // 根据实际情况处理 ansCodeBytes
            String ansCode = new String(ansCodeBytes, dmzProp.getDefaultEncoding()).trim();
            log.info("解密后的应答码为：{}", ansCode);
            return ansCode;
        } catch (Exception e) {
            throw new RuntimeException("Failed to extract ansCode", e);
        }
    }


    private boolean uploadFile(FtpFile file) {
        String fileName = file.getFileName();
        String year = fileName.substring(16, 20);
        String localPath = file.getLocalPath() + fileName;
        try {
            Ftp etcFtp = new FtpClient().etcFtp();
            String etcPath = EnvConfig.getProperty("dmz.ftp.file.path.etc") + year;
            FtpFile etcFile = new FtpFile(etcFtp, etcPath, localPath, fileName);
            FtpUtil.upload(etcFile);
            log.info("上传文件成功{}", etcFile.getFileName());
            FtpUtil.close(etcFtp);
            FileUtil.del(localPath);
            log.info("删除临时文件成功{}", etcFile.getFileName());
            return true;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }
}
